package com.ibeeking.found.cop.b.rest.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ibeeking.found.cop.b.rest.service.IGroupFriendsService;
import com.ibeeking.found.cop.service.common.dos.*;
import com.ibeeking.found.cop.service.common.enums.GroupFriendsStatusEnum;
import com.ibeeking.found.cop.service.common.enums.WxCpFriendTypeEnum;
import com.ibeeking.found.cop.service.common.param.GroupFriendsParam;
import com.ibeeking.found.cop.service.common.query.GroupFriendsPageQuery;
import com.ibeeking.found.cop.service.common.query.GroupFriendsQuery;
import com.ibeeking.found.cop.service.common.vo.GroupFriendsVO;
import com.ibeeking.found.cop.service.mapper.CopEmployeeMapper;
import com.ibeeking.found.cop.service.mapper.FriendsMapper;
import com.ibeeking.found.cop.service.mapper.GroupFriendsMapper;
import com.ibeeking.found.id.GenerateId;
import com.ibeeking.nematos.core.utils.SpringBeanUtil;
import com.ibeeking.nematos.exception.BusinessException;
import com.ibeeking.nematos.utils.bean.BeanUtil;
import com.ibeeking.nematos.utils.data.Collections3;
import com.ibeeking.nematos.utils.id.IdGenerator;
import com.ibeeking.nematos.utils.json.JsonUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @ClassName GroupFriendsServiceImpl
 * @Description
 * @Author ibeeking
 * @Date 2021-01-27 18:50
 **/
@Service
public class GroupFriendsServiceImpl extends ServiceImpl<GroupFriendsMapper, GroupFriendsDO> implements IGroupFriendsService {

    @Resource
    private GroupFriendsMapper groupFriendsMapper;

    @Resource
    private FriendsMapper friendsMapper;

    @Resource
    private CopEmployeeMapper copEmployeeMapper;

    @Override
    public List<GroupFriendsVO> list(GroupFriendsQuery query) {
        List<GroupFriendsDO> entityDOS = groupFriendsMapper.selectList(new LambdaQueryWrapper<GroupFriendsDO>()
                .eq(query.getId() != null, GroupFriendsDO::getId, query.getId())
                .eq(StringUtils.isNotBlank(query.getChatId()), GroupFriendsDO::getChatId, query.getChatId())
                .eq(query.getGroupId() != null, GroupFriendsDO::getGroupId, query.getGroupId())
                .eq(query.getFriendsId() != null, GroupFriendsDO::getFriendsId, query.getFriendsId())
                .eq(query.getFriendsType() != null, GroupFriendsDO::getFriendsType, query.getFriendsType())
                .eq(query.getFriendsJoinScene() != null, GroupFriendsDO::getFriendsJoinScene, query.getFriendsJoinScene())
                .eq(query.getInvitorId() != null, GroupFriendsDO::getInvitorId, query.getInvitorId())
                .like(StringUtils.isNotBlank(query.getFriendsCode()), GroupFriendsDO::getFriendsCode, query.getFriendsCode())
                .like(StringUtils.isNotBlank(query.getFriendsName()), GroupFriendsDO::getFriendsName, query.getFriendsName())
                .like(StringUtils.isNotBlank(query.getFriendsGroupNickname()), GroupFriendsDO::getFriendsGroupNickname, query.getFriendsGroupNickname())
                .ge(StringUtils.isNotBlank(query.getFriendsJoinTimeBegin()), GroupFriendsDO::getFriendsJoinTime, query.getFriendsJoinTimeBegin())
                .le(StringUtils.isNotBlank(query.getFriendsJoinTimeEnd()), GroupFriendsDO::getFriendsJoinTime, query.getFriendsJoinTimeEnd())
                .ge(StringUtils.isNotBlank(query.getFriendsOutTimeBegin()), GroupFriendsDO::getFriendsOutTime, query.getFriendsOutTimeBegin())
                .le(StringUtils.isNotBlank(query.getFriendsOutTimeEnd()), GroupFriendsDO::getFriendsOutTime, query.getFriendsOutTimeEnd())
                .eq(query.getStatus() != null, GroupFriendsDO::getStatus, query.getStatus())
                .orderByDesc(GroupFriendsDO::getFriendsJoinTime)
        );
        List<GroupFriendsVO> entityVOS =JsonUtils.jsonToList(entityDOS, GroupFriendsVO.class);
        if(Collections3.isNotEmpty(entityVOS)) {
            List<CopEmployeeDO> copEmployeeDOList = copEmployeeMapper.selectList(new LambdaQueryWrapper<CopEmployeeDO>());
            Map<Long, String> copEmployeeNameMaps = Collections3.isNotEmpty(copEmployeeDOList)?copEmployeeDOList.stream().collect(Collectors.toMap(CopEmployeeDO::getId, CopEmployeeDO::getEmployeeName, (o, n) -> n)):null;
            entityVOS.forEach(x -> {
                x.setInvitorName(copEmployeeNameMaps.get(x.getInvitorId()));
                x.setFriendsTypeName(WxCpFriendTypeEnum.getDescByCode(x.getFriendsType()));
                x.setStatusDesc(GroupFriendsStatusEnum.getDescByCode(x.getStatus()));
            });
        }
        return entityVOS;
    }

    @Override
    public List<GroupFriendsVO> listByGroupId(Long groupId) {
        GroupFriendsQuery query = new GroupFriendsQuery();
        query.setGroupId(groupId);
        return getBean().list(query);
    }

    @Override
    public Page<GroupFriendsVO> pageList(GroupFriendsPageQuery pageQuery) {
        LambdaQueryWrapper<GroupFriendsDO> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(pageQuery.getId() != null, GroupFriendsDO::getId, pageQuery.getId())
                .eq(StringUtils.isNotBlank(pageQuery.getChatId()), GroupFriendsDO::getChatId, pageQuery.getChatId())
                .eq(pageQuery.getGroupId() != null, GroupFriendsDO::getGroupId, pageQuery.getGroupId())
                .eq(pageQuery.getFriendsId() != null, GroupFriendsDO::getFriendsId, pageQuery.getFriendsId())
                .eq(pageQuery.getFriendsType() != null, GroupFriendsDO::getFriendsType, pageQuery.getFriendsType())
                .eq(pageQuery.getFriendsJoinScene() != null, GroupFriendsDO::getFriendsJoinScene, pageQuery.getFriendsJoinScene())
                .eq(pageQuery.getInvitorId() != null, GroupFriendsDO::getInvitorId, pageQuery.getInvitorId())
                .like(StringUtils.isNotBlank(pageQuery.getFriendsCode()), GroupFriendsDO::getFriendsCode, pageQuery.getFriendsCode())
                .like(StringUtils.isNotBlank(pageQuery.getFriendsName()), GroupFriendsDO::getFriendsName, pageQuery.getFriendsName())
                .like(StringUtils.isNotBlank(pageQuery.getFriendsGroupNickname()), GroupFriendsDO::getFriendsGroupNickname, pageQuery.getFriendsGroupNickname())
                .ge(StringUtils.isNotBlank(pageQuery.getFriendsJoinTimeBegin()), GroupFriendsDO::getFriendsJoinTime, pageQuery.getFriendsJoinTimeBegin())
                .le(StringUtils.isNotBlank(pageQuery.getFriendsJoinTimeEnd()), GroupFriendsDO::getFriendsJoinTime, pageQuery.getFriendsJoinTimeEnd())
                .ge(StringUtils.isNotBlank(pageQuery.getFriendsOutTimeBegin()), GroupFriendsDO::getFriendsOutTime, pageQuery.getFriendsOutTimeBegin())
                .le(StringUtils.isNotBlank(pageQuery.getFriendsOutTimeEnd()), GroupFriendsDO::getFriendsOutTime, pageQuery.getFriendsOutTimeEnd())
                .eq(pageQuery.getStatus() != null, GroupFriendsDO::getStatus, pageQuery.getStatus())
                .orderByDesc(GroupFriendsDO::getFriendsJoinTime);
        Page<GroupFriendsDO> entityDOPages = groupFriendsMapper.selectPage(new Page<GroupFriendsDO>(pageQuery.getPageNum(), pageQuery.getPageSize()), wrapper);
        Page<GroupFriendsVO> entityVOPages = BeanUtil.convertPage(entityDOPages, GroupFriendsVO.class);
        if(entityVOPages!=null && entityVOPages.getSize()>0) {
            List<CopEmployeeDO> copEmployeeDOList = copEmployeeMapper.selectList(new LambdaQueryWrapper<CopEmployeeDO>());
            Map<Long, String> copEmployeeNameMaps = Collections3.isNotEmpty(copEmployeeDOList)?copEmployeeDOList.stream().collect(Collectors.toMap(CopEmployeeDO::getId, CopEmployeeDO::getEmployeeName, (o, n) -> n)):null;

            entityVOPages.getRecords().forEach(f -> {
                f.setInvitorName(copEmployeeNameMaps.get(f.getInvitorId()));
                f.setFriendsTypeName(WxCpFriendTypeEnum.getDescByCode(f.getFriendsType()));
                f.setStatusDesc(GroupFriendsStatusEnum.getDescByCode(f.getStatus()));
            });
        }
        return entityVOPages;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean add(GroupFriendsParam param) {
        checkUnique(param);
        GroupFriendsDO entityDO = BeanUtil.convertBean(param, GroupFriendsDO.class);
        entityDO.setId(GenerateId.generateId());
        return groupFriendsMapper.insert(entityDO) > 0;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean modify(GroupFriendsParam param) {
        GroupFriendsDO entityDO = BeanUtil.convertBean(param, GroupFriendsDO.class);
        return groupFriendsMapper.updateById(entityDO) > 0;
    }

    @Override
    public GroupFriendsVO view(Long id) {
        GroupFriendsDO entityDO = groupFriendsMapper.selectById(id);
        if(entityDO == null) throw new BusinessException("没有查到相关记录！");
        GroupFriendsVO entityVO = BeanUtil.convertBean(entityDO, GroupFriendsVO.class);
        if(entityVO != null) {
            List<CopEmployeeDO> copEmployeeDOList = copEmployeeMapper.selectList(new LambdaQueryWrapper<CopEmployeeDO>());
            Map<Long, String> copEmployeeNameMaps = Collections3.isNotEmpty(copEmployeeDOList)?copEmployeeDOList.stream().collect(Collectors.toMap(CopEmployeeDO::getId, CopEmployeeDO::getEmployeeName, (o, n) -> n)):null;
            entityVO.setInvitorName(copEmployeeNameMaps.get(entityVO.getInvitorId()));
            entityVO.setFriendsTypeName(WxCpFriendTypeEnum.getDescByCode(entityVO.getFriendsType()));
            entityVO.setStatusDesc(GroupFriendsStatusEnum.getDescByCode(entityVO.getStatus()));
        }
        return entityVO;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean changeStatus(Long id, Integer status) {
        GroupFriendsDO entityDO = groupFriendsMapper.selectById(id);
        if(entityDO == null) throw new BusinessException("没有查到相关记录！");
        entityDO.setStatus(status);
        return groupFriendsMapper.updateById(entityDO) > 0;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean del(Long id) {
        GroupFriendsDO entityDO = groupFriendsMapper.selectById(id);
        if(entityDO == null) throw new BusinessException("没有查到相关记录！");
        return groupFriendsMapper.deleteById(id) > 0;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Integer saveOrUpdateOrDeleteBatchGroupFriends(Long tenantId, Map<Long, List<GroupFriendsDO>> groupFriendsDOMap, List<String> allFriendCodes){
        if(groupFriendsDOMap != null && groupFriendsDOMap.size() >0){
            List<Long> groupFriendsIds = new ArrayList<>();
            List<GroupFriendsDO> needInsertGroupFriendsDOS = new ArrayList<>();
            List<GroupFriendsDO> needUpdateGroupFriendsDOS = new ArrayList<>();
            List<GroupFriendsDO> needDeleteGroupFriendsDOS = new ArrayList<>();

            List<FriendsDO> friendsDOList = friendsMapper.selectList(new LambdaQueryWrapper<FriendsDO>().in(FriendsDO::getFriendsCode, allFriendCodes));
            Map<String, Long> friendsIdMaps = Collections3.isNotEmpty(friendsDOList)?friendsDOList.stream().collect(Collectors.toMap(FriendsDO::getFriendsCode, FriendsDO::getId, (o, n) -> n)):null;

            for(Long d:groupFriendsDOMap.keySet()){
                Map<String, Long> groupFriendsCodeAndIdMap = null;
                List<GroupFriendsDO> groupFriendsDOList = groupFriendsDOMap.get(d);
                List<GroupFriendsDO> oldGroupFriendsDOS = groupFriendsMapper.selectList(new LambdaQueryWrapper<GroupFriendsDO>().eq(GroupFriendsDO::getGroupId,d));
                if(Collections3.isNotEmpty(oldGroupFriendsDOS)) {
                    groupFriendsCodeAndIdMap = oldGroupFriendsDOS.parallelStream().collect(Collectors.toMap(GroupFriendsDO::getFriendsCode, GroupFriendsDO::getId, (o, n) -> o));
                    List<String> oldFriendsCodeList = oldGroupFriendsDOS.parallelStream().map(GroupFriendsDO::getFriendsCode).collect(Collectors.toList());
                    List<String> newFriendsCodeList = groupFriendsDOList.parallelStream().map(GroupFriendsDO::getFriendsCode).collect(Collectors.toList());
                    if (Collections3.isNotEmpty(oldFriendsCodeList) && Collections3.isNotEmpty(newFriendsCodeList)) {
                        HashSet<String> oldFriendsCodeHash = new HashSet<>(oldFriendsCodeList);
                        HashSet<String> newFriendsCodeHash = new HashSet<>(newFriendsCodeList);
                        oldFriendsCodeHash.removeAll(newFriendsCodeHash);
                        if (oldFriendsCodeHash.size() > 0) {
                            List<String> needDeleteFriendsCodes = new ArrayList<>(oldFriendsCodeHash);
                            List<GroupFriendsDO> needDeleteDOS = groupFriendsMapper.selectList(new LambdaQueryWrapper<GroupFriendsDO>().eq(GroupFriendsDO::getGroupId,d).in(GroupFriendsDO::getFriendsCode, needDeleteFriendsCodes));
                            needDeleteGroupFriendsDOS.addAll(needDeleteDOS);
                        }
                    }
                }
                for(GroupFriendsDO groupFriendsDO:groupFriendsDOList) {
                    Long groupFriendsId = 0L;
                    if(friendsIdMaps!=null && friendsIdMaps.size()>0){
                        Long friendId = friendsIdMaps.get(groupFriendsDO.getFriendsCode());
                        groupFriendsDO.setFriendsId(friendId!=null?friendId:null);
                    }
                    if (groupFriendsCodeAndIdMap != null && groupFriendsCodeAndIdMap.containsKey(groupFriendsDO.getFriendsCode())) {
                        groupFriendsId = groupFriendsCodeAndIdMap.get(groupFriendsDO.getFriendsCode());
                        groupFriendsDO.setId(groupFriendsId);
                        groupFriendsDO.setStatus(0);
                        needUpdateGroupFriendsDOS.add(groupFriendsDO);
                        groupFriendsIds.add(groupFriendsId);
                    } else {
                        groupFriendsId = IdGenerator.getId();
                        groupFriendsDO.setId(groupFriendsId);
                        groupFriendsDO.setStatus(0);
                        needInsertGroupFriendsDOS.add(groupFriendsDO);
                        groupFriendsIds.add(groupFriendsId);
                    }
                }
            }
            if(Collections3.isNotEmpty(needDeleteGroupFriendsDOS)){
                needDeleteGroupFriendsDOS.parallelStream().forEach(d->{
                    if(d.getFriendsOutTime() == null) {
                        d.setFriendsOutTime(LocalDateTime.now());
                    }
                    d.setStatus(1);
                });
                super.updateBatchById(needUpdateGroupFriendsDOS);
            }
            if(Collections3.isNotEmpty(needInsertGroupFriendsDOS)){
                groupFriendsMapper.insertBatchSomeColumn(needInsertGroupFriendsDOS);
            }
            if(Collections3.isNotEmpty(needUpdateGroupFriendsDOS)){
                super.updateBatchById(needUpdateGroupFriendsDOS);
            }
        }
        return 1;
    }
    /**
     * 校验唯一性
     *
     * @param param
     */
    public void checkUnique(GroupFriendsParam param) {
        if (param == null) {
            throw new BusinessException("当前记录不存在!");
        }
        //code name确保等级唯一性
        LambdaQueryWrapper<GroupFriendsDO> queryWrapper = new LambdaQueryWrapper<GroupFriendsDO>()
                .ne(param.getId() != null, GroupFriendsDO::getId, param.getId())
                .eq(GroupFriendsDO::getGroupId, param.getGroupId())
                .eq(GroupFriendsDO::getFriendsId, param.getFriendsId());
        List<GroupFriendsDO> dos = groupFriendsMapper.selectList(queryWrapper);
        if (Collections3.isNotEmpty(dos)) {
            throw new BusinessException("已经存在同名的记录!");
        }
    }

    private IGroupFriendsService getBean(){
        return SpringBeanUtil.getBean(GroupFriendsServiceImpl.class);
    }
}
